package cn.lili.modules.lucene;

import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.store.LockObtainFailedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.function.Function;

/**
 * @Author Sylow
 * @Description
 * @Date: Created in 15:39 2025/6/23
 */
@Slf4j
@Service
public class SafeIndexAccessService {
    private static final int MAX_RETRIES = 3;

    @Autowired
    private IndexStateManager stateManager;
    @Autowired
    private IndexWriterFactory writerFactory;
    @Autowired
    private SearcherManagerProvider searcherManagerProvider;

    public <T> T executeWithWriter(Function<IndexWriter, T> operation) throws LockObtainFailedException {
        ensureIndexReady();

        int attempts = 0;
        while (attempts < MAX_RETRIES) {
            try (IndexWriter writer = writerFactory.createWriter()) {
                return operation.apply(writer);
            } catch (LockObtainFailedException | IllegalStateException e) {
                attempts++;
                if (attempts >= MAX_RETRIES) throw e;
                handleRetry(attempts, e);
            } catch (IOException e) {
                throw new RuntimeException("索引操作失败", e);
            }
        }
        return null; // 永远不会执行
    }

    public <T> T executeWithSearcher(Function<IndexSearcher, T> operation) {
        ensureIndexReady();

        try {
            SearcherManager searcherManager = searcherManagerProvider.get();
            IndexSearcher searcher = searcherManager.acquire();
            try {
                return operation.apply(searcher);
            } finally {
                searcherManager.release(searcher);
            }
        } catch (IOException e) {
            throw new RuntimeException("搜索操作失败", e);
        }
    }

    private void ensureIndexReady() {
        if (stateManager.getCurrentState() != IndexState.READY) {
            throw new RuntimeException("索引未就绪，当前状态: " + stateManager.getCurrentState());
        }
    }

    private void handleRetry(int attempt, Exception e) {
        log.warn("索引操作失败 (尝试 {}), 等待后重试...", attempt, e);
        try {
            Thread.sleep(500 * attempt);
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
    }
}
